/** Media.js - Javascript functions used to display the contents of the Media Bar */

// How many pixels to jump when panning around an image
var DISPLAY_PAN_STEP = 20;

// The MediaItem the MediaPlayer is currently playing.
var hMediaPlayerPlayingItem     = null;
var hMediaPlayerNextPlayingItem = null;

// The interval used to update the duration
var hUpdateInterval = -1;

// The size of the progress bar (Filled in with correct values when the page has loaded)
var iProgressBarWidth  = 200;
var iProgressBarHeight = 10;

// Date objects for generating the playtime string
var hDate = new Date(0);

// Store the previous transport state and speed, to ensure we don't do
// any unneccessary work.
var sMediaBarPreviousState = "";
var dMediaBarPreviousSpeed = 0.0;

// Cache the various objects on the page we need to access to save looking
// them up every time
var hMediaTitleElement         = null;
var hMediaBarDuration          = null;
var hMediaBarTime              = null;
var hMediaBarProgress          = null;
var hMediaBarNext              = null;
var hMediaBarAVDisplay         = null;
var hMediaBarAlbumArt          = null;
var hMediaBarStop              = null; 
var hMediaBarPlay              = null; 
var hMediaBarPause             = null; 
var hMediaBarRewind            = null; 
var hMediaBarForward           = null; 
var hMediaBarPlaySpeed         = null;
var hMediaBarPictureDisplay    = null;
var hMediaBarPictureDate       = null;
var hMediaBarPictureZoom       = null;
var hMediaBarPictureTransition = null;

/**
 * onItemStarted
 *
 * Called when the MediaPlayer module starts to play a new MediaItem.
 *
 * @param hEvent Details of the DOM Event.
 */
function onItemStarted(hEvent) {
  var sType;
    
  // Take note of the MediaItem that is now playing
  hMediaPlayerPlayingItem     = hEvent.hMediaItemID;
  hMediaPlayerNextPlayingItem = hEvent.hNextItemID;

  // Get the resource type
  sType = MediaItem.GetProperty(hMediaPlayerPlayingItem, "type");
  
  // Is it not a picture (i.e. its Audio or Video
  if("ResourcePicture" != sType)  {
    // Update the MediaBar's display
    mediaBarDisplayTitle(MediaItem.GetProperty(hMediaPlayerPlayingItem, "title"));
    mediaBarDisplayTime(0, MediaPlayer.iCurrentDurationTime);
    
    // Display any album art
    mediaBarDisplayAlbumArt(hMediaPlayerPlayingItem);
    
    // Do we have a next track?
    mediaBarDisplayNextTrackInfo("none");
    
    // reset the transport states
    sMediaBarPreviousState = "";
    dMediaBarPreviousSpeed = 0.0;
    mediaBarDisplayState(MediaPlayer.sPlayState, MediaPlayer.dPlaySpeed);
    
    // Make sure the AVDisplay is visible
    hMediaBarAVDisplay.style.visibility = "visible";
    
    // And the picture one is hidden
    hMediaBarPictureDisplay.style.visibility = "hidden";
    
    // Create an interval to update the time and progress bar every second
    hUpdateInterval = window.setInterval(mediaBarUpdate, 1000);
  }
  // Its a picture 
  else {
    // Display the picture items
    hMediaBarPictureDisplay.style.visibility = "visible";
    
    // Hide any non-picture related items
    hMediaBarAVDisplay.style.visibility = "hidden";
    
    // Update the name
    mediaBarDisplayTitle(MediaItem.GetProperty(hMediaPlayerPlayingItem, "title"));
        
    // Display album art
    // DISCUSS: This coul be useful when rpessing next to skip lots of images
    // as it will load quicker (Should already be loaded).
    mediaBarDisplayAlbumArt(hMediaPlayerPlayingItem);

    // Set the date, zoom and current transition
    mediaBarDisplayDate(MediaItem.GetProperty(hEvent.hMediaItemID, "date"));
    mediaBarDisplayZoom(MediaPlayer.iDisplayZoom);
    mediaBarDisplayTransition(PicturePlayer.sSlideShowTransition);
  }
}

/**
 * onItemStopped
 *
 * Called when the MediaPLayer stops playing a MediaItem.
 *
 * @param hEvent Details of the DOM Event.
 */
function onItemStopped(hEvent) {
  
  // Cancel any intervals
  if(hUpdateInterval != -1) {
    window.clearInterval(hUpdateInterval);
    hUpdateInterval = -1;
  }
  
  
  // Clear the title and time
  mediaBarDisplayTitle("<unknown>");
  mediaBarDisplayTime(-1, -1);
  
  // Clear any album art
  hMediaBarAlbumArt.src = "about:blank";
  hMediaBarAlbumArt.style.visibility = "hidden";

  // Hide the displays
  hMediaBarPictureDisplay.style.visibility = "hidden";
  hMediaBarAVDisplay.style.visibility = "hidden";

  // Clear our handle of the currently playing item.
  hMediaPlayerPlayingItem = null;
  hMediaPlayerPlayingNextItem = null;


}

/**
 * mediaBarDisplayTitle
 *
 * Updates the Media Bar to display the specfied string as
 * the title of the currently playing MediaItem.
 *
 * @param sTitle The Title to display.
 */
function mediaBarDisplayTitle(sTitle) {
  // Set the title
  hMediaTitleElement.value = sTitle;
}

/**
 * mediaBarDisplayNext
 *
 * Updates the Media Bar to display the specified string as
 * the title of the next MediaItem queued up to play.
 *
 * @param sTitle The Title to display.
 */
function mediaBarDisplayNext(sTitle) {
  // Set the title
  hMediaTitleElement.value = sTitle;
}

/**
 * mediaBarDisplayDate
 *
 * Updates the Media Bar to display the specfied string as
 * the date of the currently playing MediaItem.
 *
 * @param sDate The date to display.
 */
function mediaBarDisplayDate(sDate) {
  // Currently we only display the date for pictures
  hMediaBarPictureDate.value = sDate;
}

/**
 * mediaBarDisplayZoom
 *
 * Updates the Media Bar to display the specified value as
 * the zoom level of the currently playing MediaItem.
 *
 * @param iZoom The zoom value to display
 */
function mediaBarDisplayZoom(iZoom) {
  // Currently we only display the zoom level for pictures
  hMediaBarPictureZoom.value = "" + iZoom + "%";
}

/**
 * mediaBarDisplayTransition
 *
 * Updates the Media Bar to display the specified transition
 * state.
 *
 * @param sTransition The transition to display
 */
function mediaBarDisplayTransition(sTransition) {
  // Currently we only display the transition for pictures
  hMediaBarPictureTransition.value = language.GetString("SlideShow_Transition_"+sTransition);
}

/**
 * mediaBarDisplayTime
 *
 * Updateds the Media Bar to display the specified time and
 * duration
 *
 * @param iPlayTime    The current play time
 * @param iDuration    The duration of the currently playing MediaItem
 */
function mediaBarDisplayTime(iPlayTime, iDuration) {
  var iProgress = 0;
  
  // Update the size of the progress bar.
  if(iDuration > 0) {
    iProgress = Math.round((iPlayTime / iDuration) * iProgressBarWidth);    
  }
  
  hMediaBarProgress.style.clip = "rect(0px "+iProgress+"px "+iProgressBarHeight+"px 0px)";
  
  // Set the playtime and duration
  hMediaBarTime.value     = mediaBarTimeToString(iPlayTime);
  hMediaBarDuration.value = mediaBarTimeToString(iDuration);
}

/**
 * mediaBarUpdate
 *
 * When the MediaPlayer is active, this function is called every second to
 * update the display
 */
function mediaBarUpdate() {
  // Update the time
  mediaBarDisplayTime(MediaPlayer.iCurrentPlayTime, MediaPlayer.iCurrentDurationTime);
}
 
 /**
  * mediaBarTimeToString
  *
  * Converts a millisecond time to an string containing 
  * the hours (if any) minutes and seconds
  *
  * @param iMilliSeconds The number of milli seconds to generate a time for
  *
  * @return A string format of the time (Either HH:MM:SS or MM:SS if no hours)
  */
function mediaBarTimeToString(iMilliSeconds) {
  var sTimeString = "--:--";
  
  // Check for negative values (i.e. if the time is not known)
  if(iMilliSeconds >= 0) {
    // Set the time 
    hDate.setTime(iMilliSeconds);
    sTimeString = hDate.toLocaleTimeString();
    
    // Are there any hours?
    if(0 == hDate.getUTCHours()) {    
      // IMPROVE: This relies on toLocalTimeString returning hh:mm:ss, whilst this shouldn't
      // change, it may be an idea to double check this in the setup call, and work out how many
      // characters to skip
      sTimeString = sTimeString.substr(3);
    }
  }
  
  return sTimeString;
}
  
/**
 * mediaBarDisplayAlbumArt
 *
 * Checks if the specified media item has any album art, and displays it if present.
 *
 * @param hMediaItem  The media item to display album art for
 */
function mediaBarDisplayAlbumArt(hMediaItem) {
  // Work out what resource type it is
  var sCurrentResourceType = MediaItem.GetProperty(hMediaPlayerPlayingItem, "type");

  // Is it an audio stream?
  if("ResourceAudio"         == sCurrentResourceType || 
     "ContainerServiceRadio" == sCurrentResourceType ||
     "ResourcePicture"       == sCurrentResourceType)
  {
    // Is there any meta data?
    var sAlbumArt = MediaItem.GetThumbnail(hMediaItem, 
                                           hMediaBarAlbumArt.offsetWidth, 
                                           hMediaBarAlbumArt.offsetHeight);
    
    // Was there no Metadata?
    if ("" == sAlbumArt && "ResourcePicture" != sCurrentResourceType) {
      // Use a place holder image
      sAlbumArt = "../images/default_music.png";
    }
          
    // Set the image source, and mark as visible
    hMediaBarAlbumArt.src = sAlbumArt;
    
    if("" != sAlbumArt) {
      hMediaBarAlbumArt.style.visibility = "visible";
    }
    else {
      hMediaBarAlbumArt.style.visibility = "hidden";
    }
  } 
  // Is it a video?
  else if("ResourceVideo" == sCurrentResourceType)
  {
    // Just display a placeholder
    hMediaBarAlbumArt.src = "../images/default_video.png";
    hMediaBarAlbumArt.style.visibility = "visible";
  }
  
}
  
/**
 * mediaBarDisplayNextTrackInfo
 *
 * Works out what to display in the 'next track' field, based on the specified mode
 *
 * @param sMode The play mode (one, all, shuffle etc.)
 */
function mediaBarDisplayNextTrackInfo(sMode) {
  var sCurrentResourceType = MediaItem.GetProperty(hMediaPlayerPlayingItem, "type");
   
   // Is the playlist currently empry?
  if ("EmptyPlaylist" == MediaPlayer.sPlayState) {
    // Clear the value
    hMediaBarNext.value = "<none>";
    
    return;
  }
  
  // Audio or video?
  if("ResourceAudio" == sCurrentResourceType         || 
     "ContainerServiceRadio" == sCurrentResourceType || 
     "ResourceVideo" == sCurrentResourceType)
  {
    hMediaPlayerNextPlayingItem = MediaPlayer.PlaylistGetNextTrack();

    if(hMediaPlayerNextPlayingItem)
    {
      var sMetaData = null;
      
      // If the next Item is not complete trigger an update of it now
      if("Complete" != MediaItem.GetStatus(hMediaPlayerNextPlayingItem)) 
	    {
        MediaItem.Update(hMediaPlayerNextPlayingItem);
      }
	    
	    switch(sMode) {
	      case "none":	      
     	    sMetaData = MediaItem.GetProperty(hMediaPlayerNextPlayingItem, "title");
        break;
        
        case "one":
       	  sMetaData = MediaItem.GetProperty(hMediaPlayerPlayingItem, "title");
	      break;
	      
	      case "all":
       	  sMetaData = MediaItem.GetProperty(hMediaPlayerNextPlayingItem, "title");
	      break;
	      
	      case "shuffleoff":
	        sMetaData = MediaItem.GetProperty(hMediaPlayerNextPlayingItem, "title");
        break;
      
        case "shuffle":
       	  sMetaData = MediaItem.GetProperty(hMediaPlayerNextPlayingItem, "title");
	      break;  		  
    
        default:
          sMetaData = "";
        break;
      }
      
      // Update the display
      hMediaBarNext.value = (sMetaData == null) ? "" : sMetaData; 

    } 
  } 
}

/**
 * Called when the Transport state (Play, Pause, etc.) of a MediaItem changes.
 *
 * @param hEvent Details on the transport State change event
 */
function onTransportStateChanged(hEvent) {
  
  // Is it an Audio/video MediaItem?
  if ("ResourcePicture" != MediaItem.GetProperty(hMediaPlayerPlayingItem, "type")) {
    //closePhotoInfo();
    //closePhotoFast();

    // Update the display
    mediaBarDisplayState(hEvent.sState, hEvent.dSpeed);
  }
  // Its a picture resource
  else {
/*    // Playing Picture Resource
    switch (hEvent.sState)
    {
      case "Stopped":
        closePhotoInfo();
        closePhotoFast();
        document.getElementById("stopImg").style.visibility = 'hidden';
        break;
      case "Preparing":
      case "Starving":
      case "Playing":
      case "Paused":
      default:
        break;
    }*/
  }  
}

/**
 * mediaBarDisplayState
 *
 * Called to update the Media Bar's display to reflect the specified state and
 * play speed.
 *
 * @param sState The current transport state.
 * @param dSpeed The current play speed.
 */
function mediaBarDisplayState(sState, dSpeed) {
  
  // Has the state changed?
  if(sMediaBarPreviousState != sState ||
     dMediaBarPreviousSpeed != dSpeed) 
  {
    // Default everything to hidden
    var bStopVisible = false, bPlayVisible = false, bPauseVisible = false;
    var bRewindVisible = false, bForwardVisible = false;
    var sPlaySpeed = "";
    
    switch(sState) {
      // We're now playing
      case "Playing":
        // Speed is zero, so must be paused
        if(0 == dSpeed) {
          bPauseVisible = true;
          sPlaySpeed = "";
        }
        // 1 tiems speed.  Normal playback
        else if(1 == dSpeed) {
          bPlayVisible = true;
        }
        // A negative speed, so rewinding
        else if(dSpeed < 0) {
          bRewindVisible = true;
          sPlaySpeed = "x"+(-dSpeed);
        }
        // Must be fast forward
        else {
          bForwardVisible = true;
          sPlaySpeed = "x"+dSpeed;
        }
  	  break;
  	  
  	  // We've been stopped. Display the stop icon and clear the track info
      case "Stopped":
        bStopVisible = true;
        mediaBarDisplayNextTrackInfo("none");
  	  break;
  	  
  	  // We're buffering.
      case "Preparing":
      case "Ready":
      case "Starving":
        mediaBarDisplayTitle("Please Wait...");
        mediaBarDisplayAlbumArt("");
      break;
  	    
  	  // Unhandled state, 
      default:
      break;
    }  
    
    // Update the displays
    hMediaBarStop.style.visibility    = bStopVisible    ? "inherit" : "hidden";
    hMediaBarPlay.style.visibility    = bPlayVisible    ? "inherit" : "hidden";
    hMediaBarPause.style.visibility   = bPauseVisible   ? "inherit" : "hidden";
    hMediaBarRewind.style.visibility  = bRewindVisible  ? "inherit" : "hidden";
    hMediaBarForward.style.visibility = bForwardVisible ? "inherit" : "hidden";
    hMediaBarPlaySpeed.value = sPlaySpeed;
    
    // Is we used to be in the buffering state, then redisplay the title
    if("Preparing" == sMediaBarPreviousState ||
        "Starving" == sMediaBarPreviousState)
    {
      mediaBarDisplayTitle(MediaItem.GetProperty(hMediaPlayerPlayingItem, "title"));
      mediaBarDisplayAlbumArt(hMediaPlayerPlayingItem);
      mediaBarDisplayNextTrackInfo("none");
    }

    // Remeber the previous states
    sMediaBarPreviousState = sState;
    dMediaBarPreviousSpeed = dSpeed;
  }
}

/**
 * onKeyDown
 * 
 * Called when a key is pressed on the MediaBar, or on the MediaPlayer or
 * Picture PLayer 's windows.
 *
 * @apram hEvent Details on the keypress
 *
 * @return false to claim the key (We processed it) or true to pass on
 */
function onKeyDown(hEvent) {
  var sType;
  var hPlayer = MediaPlayer;
  
  // Get the type of the curent media item, as its referenced a few times
  sType = MediaItem.GetProperty(hMediaPlayerPlayingItem, "type");
  
  // Is it a Picture?
  if("ResourcePicture" == sType) {
    // Use the PicturePlayer for sending commands to
    // IMPROVE: The MediaPlayer should really handle this internally
    hPlayer = PicturePlayer;
  }
  
  switch(hEvent.oreganKeyValueName) {
    // Pause
    case "a":
    case "A":
      hPlayer.TransportPlay(0.0);
      break;

    // Normal Play
    case "P": 
    case "p":
      hPlayer.TransportPlay(1.0);
      break;

    // Toggle Play/Pause
    case "Space":
      hPlayer.TransportTogglePlayPause();
      break;

    // Fast Forward
    case "F":
    case "f":
      hPlayer.TransportToggleFastForward();
      break;

    // FastRewind
    case "R":
    case "r": 
      hPlayer.TransportToggleFastRewind();
      break;
    
    case "n":
    case "N":
      hPlayer.TransportNextTrack();
      break;

    case "v":
    case "V":
      hPlayer.TransportPreviousTrack();
      break;

    case "Escape":
    case "Back":
      hPlayer.TransportStop();
      break;

    case "i":
    case "I":
    case "MediaSelect":
      GUI.ExecuteGUIScript("CloseWindow(Toolbar); ToggleWindow(Media)");
      break;

    case "d":
    case "D":
      hPlayer.ToggleDebugInfo();
      break;

    case "z":
    case "Z":
    case "MediaZoom":
    case "Zoom":
      hPlayer.DisplayToggleZoom();
      if("ResourcePicture" == sType)
      {
        mediaBarDisplayZoom(hPlayer.iDisplayZoom);
      }
      break;

    case "CursorRight":
      hPlayer.DisplayPan(DISPLAY_PAN_STEP, 0);
      break;

    case "CursorLeft":
      hPlayer.DisplayPan(-DISPLAY_PAN_STEP, 0);
      break;

    case "CursorDown":
      hPlayer.DisplayPan(0, DISPLAY_PAN_STEP);
      break;

    case "CursorUp":
      hPlayer.DisplayPan(0, -DISPLAY_PAN_STEP);
      break;
      
    case "Red":     // Rotate
      if ("ResourcePicture" == sType) {
        hPlayer.iDisplayRotate = (hPlayer.iDisplayRotate + 90) % 360
      }
      break;
      
    case "Green":   // Zoom
      if ("ResourcePicture" == sType) {
        hPlayer.DisplayToggleZoom();
        mediaBarDisplayZoom(hPlayer.iDisplayZoom);
      }
      break;

    case "Yellow":  // Information
    break;

    case "Blue":    // Transition
      if ("ResourcePicture" == sType) {
        // Move on to the next transition
        for(var iTransition = 0; 
                iTransition < hPlayer.SlideShowGetNumberTransitions(); 
                iTransition++)
        {
          if(hPlayer.SlideShowGetTransitionName(iTransition) == hPlayer.sSlideShowTransition)
          {
            iTransition = (iTransition + 1) % hPlayer.SlideShowGetNumberTransitions();
            hPlayer.sSlideShowTransition = hPlayer.SlideShowGetTransitionName(iTransition);
            break;
          }
        }
        mediaBarDisplayTransition(PicturePlayer.sSlideShowTransition);
      }
      break;

    case "Setup":
      // Disable setup when playing video/pictures
      if("ResourceVideo" != sType && "ResourcePicture" != sType)
      {
        // Pass on top default handler
        return true;
      }
      break;
      
    case "WebHome":
    case "ViewAudio":
    case "ViewVideo":
    case "ViewPictures":
      if ( "ResourceVideo" == sType || "ResourcePicture" == sType )
      {
        hPlayer.TransportStop();
      }
      
      // Pass on to main window
      if(window.topLevelWindow && window.topLevelWindow.KeyAction) {
        window.topLevelWindow.KeyAction(hEvent);
      }
      break;

    default:
      // Not handled, pass on
      return true;
  }

  return false;
}

/**
 * setup
 *
 * Called when the window has finished loading, allowing
 * us to perform the neccessary setup code.
 *
 * @param hEvent Details of the event
 */
function setup(hEvent) {
  // Cache some objects
  hMediaTitleElement         = document.getElementById("MediaBarTitle");
  hMediaBarDuration          = document.getElementById("MediaBarDuration");
  hMediaBarTime              = document.getElementById("MediaBarTime");
  hMediaBarProgress          = document.getElementById("MediaBarProgress");
  hMediaBarNext              = document.getElementById("MediaBarNext");
  hMediaBarAVDisplay         = document.getElementById("MediaBarAVDisplay");
  hMediaBarAlbumArt          = document.getElementById("MediaBarAlbumArt");
  hMediaBarStop              = document.getElementById("MediaBarStop"); 
  hMediaBarPlay              = document.getElementById("MediaBarPlay"); 
  hMediaBarPause             = document.getElementById("MediaBarPause"); 
  hMediaBarRewind            = document.getElementById("MediaBarRewind"); 
  hMediaBarForward           = document.getElementById("MediaBarForward"); 
  hMediaBarPlaySpeed         = document.getElementById("MediaBarPlaySpeed"); 
  hMediaBarPictureDisplay    = document.getElementById("MediaBarPictureDisplay");
  hMediaBarPictureDate       = document.getElementById("MediaBarPictureDate");
  hMediaBarPictureZoom       = document.getElementById("MediaBarPictureZoom");
  hMediaBarPictureTransition = document.getElementById("MediaBarPictureTransition");
 
  // Work out how wide the progress bar should be
  // IMPROVE Should be using offsetLeft to work this all out exactly
  iProgressBarWidth  = hMediaBarAVDisplay.offsetWidth - hMediaBarDuration.offsetWidth - hMediaBarTime.offsetWidth - 10;
  iProgressBarHeight = hMediaBarProgress.offsetHeight;
  
  // Set the new width
  hMediaBarProgress.style.width = iProgressBarWidth + "px";
  
  // Register the MediaPlayer events (This currently only triggers Audio and video events)
  MediaPlayer.onItemStarted = onItemStarted;
  MediaPlayer.onItemStopped = onItemStopped;
  MediaPlayer.onTransportStateChanged = onTransportStateChanged;  
  
  // Register PicturePlayer events
  PicturePlayer.onItemStarted = onItemStarted;
  PicturePlayer.onItemStopped = onItemStopped;

  // Tell the media andpicture player which GUI window to send any kepresses it receives to
  MediaPlayer.SetKeyHandlerWindow("Media");
  //MediaPlayer.SetMouseHandlerWindow("Media");
  PicturePlayer.SetKeyHandlerWindow("Media");
  //PicturePlayer.SetMouseHandlerWindow("Media");
  
}

// Attach this event
window.addEventListener("load", setup, false);


